#ifndef a8_thread_h
#define a8_thread_h

#include <assert.h>
#include <pthread.h>
#include <a8/atomic.hpp>
#include <a8/delegate.hpp>

namespace a8
{
    static void* ThreadWrapper(void* threadParam);

    class Thread
    {
    public:
        Thread():mShutdown(0)
        {
            memset(&mId, 0, sizeof(pthread_t));
        }

        virtual ~Thread()
        {
            Stop();
            Join();
        }

        void Start()
        {
            assert(!IsValidThread());
            if(pthread_create(&mId, 0, ThreadWrapper, this) != 0){
                mShutdown = 0;
			}
        }

        virtual void Stop()
        {
            InterlockedIncrement(&mShutdown);
        }

		bool IsValidThread()
		{
			pthread_t emptyId;
			memset(&emptyId, 0, sizeof(pthread_t));
			return memcmp(&mId, &emptyId, sizeof(mId)) != 0;
		}

        void Join()
        {      
			if(!IsValidThread()){
				return;
			}
			pthread_t selfthread = pthread_self();
			if (memcmp(&mId, &selfthread, sizeof(mId)) != 0){
				void * stat;
				int r = pthread_join(mId, &stat);
                if(r != 0){
					assert(0);
				}
            }
            memset(&mId, 0, sizeof(pthread_t));
        }

        bool IsShutdown()
        {
            return mShutdown == 1;
        }

		virtual void ThreadFunc() {};
    protected:
        volatile unsigned long mShutdown;
        pthread_t mId;
    };

    static void* ThreadWrapper(void* threadParam)
    {
        Thread* t = static_cast<Thread*>(threadParam);
        assert(t);
        t->ThreadFunc();
        return 0;
    }

    class Runnable: public Thread
    {
    public:
        a8::Delegate<void (Runnable*)> OnExecute;

        Runnable():Thread() {}
        virtual void ThreadFunc()
        {
            OnExecute(this);
        }
    };
}

#endif
